#include <iostream>
#include "i_include.cpp"

// number of iterations to perform of each test
int const NUM_OF_TESTS = 15;

int main(int argc, char** argv)
{
	int i, j, c, x, y, z; game_setup(GAME);
	
	// setup trace log for unit testing
	TRACE_LEVEL = TRACE_LEVEL_INFO;
	
	// ##### test 1: accurate evaluation of positional and material value
	trace(TRACE_LEVEL_INFO, NEWLINE, "BEGAN Test 1 (Positional and Material Value).");
	I_CHESS_POSITION* board1 = start_board(); MOVELIST moves;
	
	for (i = 0; i < NUM_OF_TESTS; ++i)
	{
		// get the current player and legal moves
		moves = gen_move_list(board1);
		c = board1->col;
		
		for (j = 0; j < moves.size; ++j)
		{
			// retrieve the "modified" pos/mat values
			x = moves.arr[j]->board[MOVE_TO]->pos[c];
			y = moves.arr[j]->board[MOVE_TO]->mat[c];
			
			// compute the pos/mat values naively
			eval_material_value(moves.arr[j]->board[MOVE_TO]);
			
			// assert that these two values are identical
			trace_assert(x == moves.arr[j]->board[MOVE_TO]->pos[c], "FAILED to match positional values.");
			trace_assert(y == moves.arr[j]->board[MOVE_TO]->mat[c], "FAILED to match material values.");
		};
		
		// apply a random move, and continue
		apply_move(board1, moves.arr[rand() % j]);
		
		// free move list before we continue
		free_move_list(moves);
	};
	
	// free the board
	delete board1;
	
	// test 1: print success message
	trace(TRACE_LEVEL_INFO, "SUCCESSFULLY completed Test 1.");
	
	// ##### test 2: get some "random" values from mt_rand32();
	trace(TRACE_LEVEL_INFO, NEWLINE, "BEGAN Test 2 (Mersenne Twister PRNG).");
	
	// setup mersenne twister and generate many random numbers
	for (i = 0; i < 1000; ++i) mt_rand32();
	
	// test 2: print success message
	trace(TRACE_LEVEL_INFO, "SUCCESSFULLY completed Test 2.");
	
	// ##### test 2: get some "random" values from mt_rand32();
	trace(TRACE_LEVEL_INFO, NEWLINE, "BEGAN Test 3 (Hash-and-Lock Symmetry).");
	
	// setup another board to run tests on
	I_CHESS_POSITION* board2 = start_board();
	
	// test all hash and lock values
	for (i = 0; i < I_BOARD_TRUE_RANK; ++i)
	for (j = 0; j < I_BOARD_TRUE_RANK; ++j)
	{
		// black perspective rank
		x = I_BOARD_TRUE_RANK - (i + 1);
	
		// for all pieces
		for (z = 0; z < I_PIECE_COUNT; ++z)
		{
			// check all piece values (switching piece value to switch perspective)
			trace_assert(GAME.ZKEYS[I_SIDE_WHITE][i][j][z] == GAME.ZKEYS[I_SIDE_BLACK][x][j][z ^ 1], "FAILED to match piece-location hash subentries.");
			trace_assert(GAME.ZLOCK[I_SIDE_WHITE][i][j][z] == GAME.ZLOCK[I_SIDE_BLACK][x][j][z ^ 1], "FAILED to match piece-location lock subentries.");
		};
		
		// check empty board as well. these MUST match
		trace_assert(GAME.ZKEYS[I_SIDE_WHITE][i][j][z] == GAME.ZKEYS[I_SIDE_BLACK][x][j][z], "FAILED to match empty board hash subentries.");
		trace_assert(GAME.ZLOCK[I_SIDE_WHITE][i][j][z] == GAME.ZLOCK[I_SIDE_BLACK][x][j][z], "FAILED to match empty board lock subentries.");
	};
	
	// assert equality for starting board values
	trace_assert(board_hash(board2, I_SIDE_WHITE) == board_hash(board2, I_SIDE_BLACK), "FAILED to match symmetric boards");
	
	// free the board
	delete board2;
	
	// test 2: print success message
	trace(TRACE_LEVEL_INFO, "SUCCESSFULLY completed Test 3.");
};
